﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio;
using System.CodeDom.Compiler;
using System.Runtime.InteropServices;
using System.CodeDom;
using System.Xaml;

namespace UIT.VisualStudioHelper
{
    public class CodeGenerator : IVsSingleFileGenerator
    {
        #region IVsSingleFileGenerator Members

        public int DefaultExtension(out string pbstrDefaultExtension)
        {
            pbstrDefaultExtension = "xaml";
            return VSConstants.S_OK;
        }

        public int Generate(string wszInputFilePath, string pInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
        {
            if (pInputFileContents == null)
                throw new ArgumentNullException(pInputFileContents);

            // Création du fournisseur de code permettant de transformer un graphe d'instructions et d'expressions en code
            CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("C#");
            string fullClassName=FindClassFullName(pInputFileContents);

            CodeCompileUnit code = new CodeCompileUnit();
            CodeNamespace ns=new CodeNamespace(fullClassName.Substring(0,fullClassName.LastIndexOf('.')));
            code.Namespaces.Add(ns);

            CodeTypeDeclaration @class = new CodeTypeDeclaration(fullClassName.Substring(ns.Name.Length + 1));
            ns.Types.Add(@class);

            @class.IsPartial = true;

            CodeMemberMethod initializeComponent = new CodeMemberMethod();
            @class.Members.Add(initializeComponent);

            initializeComponent.Name = "InitializeComponent";
            initializeComponent.Statements.Add(new CodeMethodInvokeExpression(
                new CodeMethodReferenceExpression(
                    new CodeTypeReference(typeof(RendererManager)), 
                    "CreateInstance", 
                    new CodeTypeReference()))

            if (generatedStuff == null)
            {
                pOutputFileContents[0] = IntPtr.Zero;
                pOutputFileContentSize = 0;
            }
            else
            {
                // Copie du flux en mémoire pour que Visual Studio puisse le récupérer
                pOutputFileContents[0] = Marshal.AllocCoTaskMem(generatedStuff.Length);
                Marshal.Copy(generatedStuff, 0, pOutputFileContents[0], generatedStuff.Length);
                pOutputFileContentSize = (uint)generatedStuff.Length;
            }

            return VSConstants.S_OK;
        }

        private string FindClassFullName(string pInputFileContents)
        {
            bool readValue = false;
            using (XamlReader reader = new XamlXmlReader(pInputFileContents))
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XamlNodeType.StartMember)
                    {
                        if (reader.Member.PreferredXamlNamespace == "http://schemas.microsoft.com/winfx/2006/xaml")
                            readValue = true;
                    }
                    if (reader.NodeType == XamlNodeType.Value && readValue)
                    {
                        return reader.Value.ToString();
                    }
                }
            }
            return null;
        }

        #endregion
    }
}
